package MathCore.Operators;

import MathCore.Lexeme;
import MathCore.Operand;
import MathCore.Operands.Complex;
import MathCore.Operands.List;
import MathCore.Operands.Number;

public class BasicFunction extends Function
{
	public static final int ABS	=1;
	public static final int SQRT	=2;
	public static final int LOG	=3;
	public static final int LN	=4;
	public static final int FACT	=5;
	public static final int INVERT	=6;

	public BasicFunction()
	{
		super(0);
	}

	public BasicFunction(int t)
	{
		super(t);
	}

	public BasicFunction(BasicFunction b)
	{
		super(b.type);
	}

	public Operand exec(Operand[] operands) throws OperatorException
	{
		if(operands.length != params())
			throw new OperatorException("Неправильное количество операндов у функции "+toString()+". Необходимо "+params()+".");

		if(have(operands, List.class)) return expandListsLinear(operands, this);

		else if(only(operands, Number.class))
		{
			
			Number result = new Number( (Number) operands[0]);
			switch(type)
			{
				case ABS:
					result.get().abs();
					break;

				case LN:
					result.get().ln();
					break;

				case FACT:
					result.get().fact();
					break;

				case SQRT:
					result.get().sqrt();
					break;

				case INVERT:
					result.get().mul(-1);
					break;

				case LOG:
					result = new Number( (Number) operands[0]);
					Number temp = new Number( (Number) operands[1]);
					result.get().log2();
					temp.get().log2();
					result.get().rdiv(temp.get());
					break;
			}

			return result;
		}
		else if(operands[0] instanceof Complex)
		{
			Complex cmp = (Complex) operands[0];
			switch(type)
			{
				case ABS: return new Number(cmp.abs());
			}
			
			throw new OperatorException(OperatorException.UNSUPPORTED_COMBINATION);
		}
		else
		{
			throw new OperatorException(OperatorException.UNSUPPORTED_COMBINATION);
		}
	}

	public int params()
	{
		switch(type)
		{
			case ABS:
			case SQRT:
			case LN:
			case FACT:
			case INVERT:
				return 1;

			case LOG:
				return 2;
		}

		return 0;
	}

	public String toString()
	{
		switch(type)
		{
			case ABS:
				return "abs";

			case SQRT:
				return "sqrt";

			case LN:
				return "ln";

			case FACT:
				return "fact";

			case LOG:
				return "log";

			case INVERT:
				return "-";
		}

		return "";
	}

	public Lexeme clone()
	{
		return new BasicFunction(this);
	}
}
